using System;
using System.Xml.Linq;

namespace Driven.ProcessScheduler.Conversion
{
    public class XmlScheduleConvertor : IScheduleConvertor
    {
        public string Convert(ScheduleManager scheduleManager)
        {
            return new XDocument(
                new XElement("configuration",
                             createDescriptionComment(),
                             new XElement("components",
                                          createScheduleManager(scheduleManager),
                                          Array.ConvertAll(scheduleManager.Schedules.ToArray(), s => createSchedule(s)),
                                          Array.ConvertAll(scheduleManager.Schedules.ToArray(), s => createComponent(s.Component))
                                 )
                    )).ToString();
        }

        private XComment createDescriptionComment()
        {
            return new XComment(@"The ScheduleManager component has a list of Schedules. Each Schedule executes an ScheduledComponent at a specified time of 
	   day, or at a specific time of day. There are currently two example processes listed below, ScheduleA which executes 
	   TestScheduledComponent1 and ScheduleB which executes TestScheduledComponent2. 
				
	   Your own processes are added using the following three steps:
		  1.	Create a ScheduledComponent (e.g. TestScheduledComponent1)
		  2.	Create a Schedule (e.g. ScheduleA) and link it to your ScheduledComponent
		  3.	Add your Schedule to the ScheduleManager array of Schedules
		
	   NB: You should remove the example processes before you try to run the ProcessScheduler service.");
        }

        private XElement createScheduleManager(ScheduleManager manager)
        {
            return new XElement("component", 
                                new XAttribute("id", "ScheduleManager"),
                                new XAttribute("type", "Driven.ProcessScheduler.ScheduleManager, Driven.ProcessScheduler"),
                                new XElement("parameters",
                                             new XElement("schedules",
                                                          new XElement("array", 
                                                                       new XAttribute("type", "Driven.ProcessScheduler.Schedule, Driven.ProcessScheduler"),
                                                                       Array.ConvertAll(manager.Schedules.ToArray(), s => new XElement("item", String.Format("${{{0}}}", s.Name))),
                                                                       new XComment("<item> another schedule here </item> ")))));
        }

        private object[] createSchedule(Schedule s)
        {
            return new object[]
                       {
                           new XComment(string.Format(" ===== {0} ===== ", s.Name)),
                           new XComment("NB: There are two options for scheduling - either time of day (timeSchedule) OR repeat every n number of minutes (repetitionSchedule) "),
                           new XElement("component",
                                        new XAttribute("id", s.Name),
                                        new XAttribute("type", "Driven.ProcessScheduler.Schedule, Driven.ProcessScheduler"),
                                        new XElement("parameters",
                                                     new XComment(" The display name of the Schedule "),
                                                     new XElement("name", s.Name),
                                                     new XComment(" The component that this Schedule will execute on schedule "),
                                                     new XElement("component", "${" + s.Component.ToString() + "}"),
                                                     new XComment(" The time of day that the schedule should execute (HH:MM, 00:00 means to not execute at a specific time) "),
                                                     new XElement("timeSchedule", s.TimeSchedule),
                                                     new XComment(" The amount of time between executions of the schedule (in minutes, 0 means to not execute repetetively "),
                                                     new XElement("repetitionSchedule", s.RepetitionSchedule)
                                            )
                               )};
        }

        private object[] createComponent(IScheduledComponent c)
        {
            return new object[]
                       {
                           new XComment("===== " + c.ToString() + " : The implementation of IScheduledComponent that actually does the work ====="),
                           new XElement("component", 
                                        new XAttribute("id", c.ToString()),
                                        new XAttribute("service", "Driven.ProcessScheduler.IScheduledComponent, Driven.ProcessScheduler"),
                                        new XAttribute("type", c.GetType().AssemblyQualifiedName))
                       };
        }
    }
}